#pragma once

#include <vector>
#include <boostext/iostreams/bin_ostream.hpp>
#include <boostext/iostreams/bin_istream.hpp>

#include "exports.hpp"
#include "pointer.hpp"




namespace Engine
{
	namespace Script
	{
		class ENGINE_SCRIPT_API Type;
		class ENGINE_SCRIPT_API Reflectable;

		/**
		 * This class is a small wrapper around asIScriptFunction
		 * and exposes it's entire interface in a more user friendly
		 * way.
		 */
		class ENGINE_SCRIPT_API Function
		{
		public:

			typedef boost::optional<Function>   opt;

			Function(boost::weak_ptr<const Reflectable> reflectable, pointer<asIScriptFunction> handle);
			virtual ~Function();



			/**
			 * @returns the id of this function
			 */
			int id() const;

			/**
			 * @returns the name of this function
			 */
			QString name() const;

			/**
			 * @returns the declaration of the function/method
			 *
			 * If this value is required often, then it is advised
			 * to cache the value: It doesn't change over the lifetime
			 * of a Function.
			 */
			QString declaration() const;



			/**
			 * Tests if this function is actually a free function.
			 * It's only free when it's no class method and no interface method.
			 */
			bool isFreeFunction() const;

			/**
			 * Tests if this function is actually a class method.
			 */
			bool isClassMethod() const;

			/**
			 * Tests if this function is an interface method.
			 */
			bool isInterfaceMethod() const;

			/**
			 * Tests if this method is read only.
			 *
			 * @returns false when this is no method
			 */
			bool isReadOnly() const;

			/**
			 * @returns the object type this function belongs to, if it's a method
			 * @returns an empty type if this is a free function or a method
			 */
			boost::optional<Type> objectType() const;



			/**
			 * @returns the return type of this function
			 */
			Type returnType() const;

			/**
			 * @returns the number of arguments
			 */
			int argumentCount() const;

			/**
			 * @returns the nth argument
			 * @throws if there is no such argument
			 */
			Type argument(int index) const;



			/**
			 * Compares this functions state agains the one in the given stream
			 * and throws if there are differences.
			 */
			void compareState(boostext::iostreams::bin_istream& stream) const;

			/**
			 * Serializes most relevant information of this type.
			 */
			void saveState(boostext::iostreams::bin_ostream& stream) const;

		protected:

			/**
			 * @returns a pointer to the system
			 */
			boost::shared_ptr<const Reflectable> reflectable() const;

		private:

			#pragma warning (push)
			#pragma warning (disable: 4251)
			boost::weak_ptr<const Reflectable>   m_reflectable;
			#pragma warning (pop)
			pointer<asIScriptFunction>           m_handle;
		};
		///////////////////////////////////////////////////////////////////////////////////////////

		/// Typedef for the callstack
		typedef std::vector<Function>   Callstack;
	}
	///////////////////////////////////////////////////////////////////////////////////////////////
}
///////////////////////////////////////////////////////////////////////////////////////////////////
